/**
 * @file Value.hh
 * @author Xiaoze Lin (linxiaoze96@gmail.com)
 * @brief The value class.
 * @version 0.1
 *
 * @copyright Copyright (c) 2024
 *
 */
#pragma once
#include <immintrin.h>

#include <cstdint>

#include "define/Define.hh"

#define NUM_OF_BITS 64
#define NUM_OF_BITS_256 256

struct __m256i_wrapper
{
  __m256i int256;
};

namespace ifsim {

static const char* LUT_ValueToString[2][2] = {"0", "Z", "X", "1"};

// bit0 = 0 bit1 = 0 represent 0
// bit0 = 1 bit1 = 1 represent 1
// bit0 = 1 bit1 = 0 represent X
// bit0 = 0 bit1 = 1 represent Z
class Value
{
 public:
  Value();
  Value(uint64_t bit0, uint64_t bit1);
  ~Value() { ; }

  bool operator==(const Value& other_value);
  bool operator!=(const Value& other_value);

  uint64_t bit0() { return _bit0; }
  void bit0(uint64_t bit0) { _bit0 = bit0; }

  uint64_t bit1() { return _bit1; }
  void bit1(uint64_t bit1) { _bit1 = bit1; }

  void setSingle1();
  void setSingle0();
  void setSingleX();
  void setSingleZ();

  void setParallel1();
  void setParallel0();
  void setParallelX();
  void setParallelZ();

  void setVal1(int num_bits);
  void setVal0(int num_bits);

  void setValue(uint64_t bit0, uint64_t bit1);

  void expandOneBitToValue(bool bit0, bool bit1);

 private:
  uint64_t _bit0;
  uint64_t _bit1;
};

class Value256
{
 public:
  Value256();
  Value256(__m256i_wrapper bit0, __m256i_wrapper bit1);
  ~Value256() { ; }

  bool operator==(const Value256& other_value);
  bool operator!=(const Value256& other_value);

  __m256i_wrapper bit0() { return _bit0; }
  void bit0(__m256i_wrapper bit0) { _bit0 = bit0; }

  __m256i_wrapper bit1() { return _bit1; }
  void bit1(__m256i_wrapper bit1) { _bit1 = bit1; }

  void setSingle1();
  void setSingle0();
  void setSingleX();
  void setSingleZ();

  void set256Parallel1();
  void set256Parallel0();
  void set256ParallelX();
  void set256ParallelZ();

  void setVal1(int num_bits);
  void setVal0(int num_bits);

  void setValue(__m256i_wrapper bit0, __m256i_wrapper bit1);

  void setOneBitVal(uint64_t bit_val, uint64_t other_bit_val, int bit_id);
  void expandValueToValue256(Value val);
  void expandOneBitToValue256(bool bit0, bool bit1);

 private:
  __m256i_wrapper _bit0;
  __m256i_wrapper _bit1;
};
}  // namespace ifsim